/*--------------------------------------------------------------------------
Modified from GNU Group's SDCC
Only for study purpose
---------------------------------------------------------------------------*/

#include <stdio.h>
#include "common.h"
#include "iCode.h"
#include "Parser.h"

#define _first_phase_
set *iCodeChain = NULL;
int iTempNum = 0;
int iTempLblNum = 0;
int operandKey = 0;
int iCodeKey = 0;
char *filename;                 /* current file name */
int lineno = 1;                 /* current line number */
int block;
int scopeLevel;
int seqPoint;
extern int NestLevel;
extern char labelbuffer[MAX_LENGTH_BUFFER];
int bSkipGenGetAddress = 0;
/*
	Operand structure's supported function
	Created by nvcuong 
	Reference from SDCC's SDCCicode.c$
*/


void _error()
{
	SYNTAX_ERROR;
}
/*-----------------------------------------------------------------*/
/* newOperand - allocate, init & return a new iCode                */
/*-----------------------------------------------------------------*/

operand *newOperand ()
{
	operand *op;
	op = Safe_alloc ( sizeof (operand));

	op->key = 0;
	return op;
}


/*-----------------------------------------------------------------*/
/* operandFromSymbol - creates an operand from a symbol            */
/*-----------------------------------------------------------------*/

operand *operandFromSymbol (symbol * sym)
{
	operand *op;
	iCode *ic;
	sym_link *link;
	//if (IS_LITERAL (sym->etype) && SPEC_ENUM (sym->etype))
	//  return operandFromValue (valFromType (sym->etype));
	if (bSkipGenGetAddress || !IS_AGGREGATE(sym->type))
	{
		op = newOperand ();
		op->type = SYMBOL;
		op->operand.symOperand = sym;
		op->key = sym->key;
		bSkipGenGetAddress = 0;
		return op;
	}

	ic = newiCode (ADDRESS_OF, newOperand (), NULL);
	IC_LEFT (ic)->type = SYMBOL;
	IC_LEFT (ic)->operand.symOperand = sym;
	IC_LEFT (ic)->key = sym->key;
	(IC_LEFT (ic))->isGlobal = isOperandGlobal (IC_LEFT (ic));
	IC_LEFT (ic)->isPtr = IS_PTR (operandType (IC_LEFT (ic)));

	/* create result */
	link = newLink(DECLARATOR);
	DCL_TYPE(link) = POINTER;
	link->next = copyLinkChain(sym->type);

	IC_RESULT (ic) = newiTempOperand (link, 0);
	IC_RESULT (ic)->isaddr = (!IS_AGGREGATE (link));
	ADDTOCHAIN (ic);

	return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* operandFromValue - creates an operand from value                */
/*-----------------------------------------------------------------*/
operand *operandFromValue (value * val)
{
  operand *op;
  if (val->sym)
    return operandFromSymbol (val->sym);

  op = newOperand ();
  op->type = VALUE;
  op->operand.valOperand = val;
  return op;
}

/*-----------------------------------------------------------------*/
/* operandFromLink - operand from typeChain                        */
/*-----------------------------------------------------------------*/
operand *operandFromLink (sym_link * type)
{
	operand *op;
	if (!type)
		return NULL;
	op = newOperand ();
	op->type = TYPE;
	op->operand.typeOperand = copyLinkChain (type);
	return op;
}

/*-----------------------------------------------------------------*/
/* newiTemp - allocate & return a newItemp Variable                */
/*-----------------------------------------------------------------*/
symbol *newiTemp (char *s)
{
	char buffer[100];
	symbol *itmp;

	if (s)
		sprintf (buffer, "%s", s);
	else
		sprintf(buffer, "iTemp%d", iTempNum++);

	itmp = newSymbol (buffer, 1);
	strncpy (itmp->rname, itmp->name, MAX_NAME);
	itmp->isitmp = 1;

	return itmp;
}

/*-----------------------------------------------------------------*/
/* newiTempOperand - new intermediate temp operand                 */
/*-----------------------------------------------------------------*/
operand *newiTempOperand (sym_link * type, char throwType)
{
	symbol *itmp;
	operand *op = newOperand ();
	sym_link *etype;

	op->type = SYMBOL;
	itmp = newiTemp (NULL);

	etype = getSpec (type);

	if (IS_LITERAL (etype))
		throwType = 0;

	/* copy the type information */
	if (type)
		itmp->etype = getSpec (itmp->type = (throwType ? type : copyLinkChain (type)));
	if (IS_LITERAL (itmp->etype))
		SPEC_SCLS (itmp->etype) = S_REGISTER;

	op->operand.symOperand = itmp;
	op->key = itmp->key = ++operandKey;
	return op;
}

sym_link *operandType (operand * op)
{
  /* depending on type of operand */
	switch (op->type)
	{
	case VALUE:
	  return op->operand.valOperand->type;

	case SYMBOL:
	  return op->operand.symOperand->type;

	case TYPE:
	  return op->operand.typeOperand;

	default:
		SYNTAX_ERROR;
		return (sym_link *) 0;
	}
}

/*
	iCode structure's supported function
	Created by nvcuong 
	Reference from SDCC's SDCCicode.c
*/

/*-----------------------------------------------------------------*/
/* newiCode - create and return a new iCode entry initialised      */
/*-----------------------------------------------------------------*/
iCode *newiCode (int op, operand * left, operand * right)
{
  iCode *ic;

  ic = Safe_alloc ( sizeof (iCode));

  ic->seqPoint = seqPoint;
  ic->filename = filename;
  ic->lineno = lineno;
  ic->block = block;
  ic->level = scopeLevel;
  ic->op = op;
  ic->key = iCodeKey++;
  IC_LEFT (ic) = left;
  IC_RIGHT (ic) = right;

  return ic;
}


/*
	iCode's generation
	Created by nvcuong 
*/


/*-----------------------------------------------------------------*/
/* newiCodeLabelGoto - unconditional goto statement| label stmnt   */
/*-----------------------------------------------------------------*/
iCode *newiCodeLabelGoto (int op, symbol * label)
{
  iCode *ic;

  ic = newiCode (op, NULL, NULL);
  ic->op = op;
  ic->label = label;
  IC_LEFT (ic) = NULL;
  IC_RIGHT (ic) = NULL;
  IC_RESULT (ic) = NULL;
  return ic;
}

/*-----------------------------------------------------------------*/
/* copyiCode - make a copy of the iCode given                      */
/*-----------------------------------------------------------------*/
iCode *copyiCode (iCode * ic)
{
	return NULL;
}


/*-----------------------------------------------------------------*/
/* operandSize - returns size of an operand in bytes               */
/*-----------------------------------------------------------------*/
unsigned int operandSize (operand * op)
{
  sym_link *type;

  /* if nothing return 0 */
  if (!op)
    return 0;

  type = operandType (op);
  if (op->aggr2ptr == 2)
    type = type->next;
  return getSize (type);
}

/*-----------------------------------------------------------------*/
/* isParamterToCall - will return 1 if op is a parameter to args   */
/*-----------------------------------------------------------------*/
int isParameterToCall (value * args, operand * op)
{
 // value *tval = args;

 ////wassert (IS_SYMOP(op));

 // while (tval)
 //   {
 //     if (tval->sym && isSymbolEqual (op->operand.symOperand, tval->sym))
 //       return 1;
 //     tval = tval->next;
 //   }
  return 0;
}

/*-----------------------------------------------------------------*/
/* isOperandGlobal   - return 1 if operand is a global variable    */
/*-----------------------------------------------------------------*/
int isOperandGlobal (operand * op)
{
  if (!op)
    return 0;

  if (IS_ITEMP (op))
    return 0;

  if (IS_SYMOP(op) &&
      (op->operand.symOperand->level == 0 ||
       IS_STATIC(op->operand.symOperand->etype) ||
       IS_EXTERN (op->operand.symOperand->etype))
    )
    return 1;

  return 0;
}


/*-----------------------------------------------------------------*/
/* isOperandLiteral - returns 1 if an operand contains a literal   */
/*-----------------------------------------------------------------*/
int isOperandLiteral (operand * op)
{
  sym_link *opetype;

  if (!op)
    return 0;

  opetype = getSpec (operandType (op));

  if (IS_LITERAL (opetype))
    return 1;

  return 0;
}

/*-----------------------------------------------------------------*/
/* operandLitValue - literal value of an operand                   */
/*-----------------------------------------------------------------*/
long operandLitValue (operand * op)
{
  assert (isOperandLiteral (op));

  return ulFromVal (op->operand.valOperand);
}

/*-----------------------------------------------------------------*/
/* newiTempFromOp - create a temp Operand with same attributes     */
/*-----------------------------------------------------------------*/
operand *newiTempFromOp (operand * op)
{
  operand *nop;

  if (!op)
    return NULL;

  if (!IS_ITEMP (op))
    return op;

  nop = newiTempOperand (operandType (op), true);
  nop->isaddr = op->isaddr;
  nop->isvolatile = op->isvolatile;
  nop->isGlobal = op->isGlobal;
  nop->isLiteral = op->isLiteral;
  nop->isParm = op->isParm;
  return nop;
}

/*-----------------------------------------------------------------*/
/* operand from operand - creates an operand holder for the type   */
/*-----------------------------------------------------------------*/
operand *operandFromOperand (operand * op)
{
	operand *nop;

	if (!op)
		return NULL;
	nop = newOperand ();
	nop->type = op->type;
	nop->isaddr = op->isaddr;
	nop->key = op->key;
	nop->isvolatile = op->isvolatile;
	nop->isGlobal = op->isGlobal;
	nop->isLiteral = op->isLiteral;
	nop->isParm = op->isParm;

	switch (nop->type)
	{
		case SYMBOL:
		  nop->operand.symOperand = op->operand.symOperand;
		  break;
		case VALUE:
		  nop->operand.valOperand = op->operand.valOperand;
		  break;
		case TYPE:
		  nop->operand.typeOperand = op->operand.typeOperand;
		  break;
	}

	return nop;
}


/*-----------------------------------------------------------------*/
/* setOperandType - sets the operand's type to the given type      */
/*-----------------------------------------------------------------*/
void setOperandType (operand * op, sym_link * type)
{
  /* depending on the type of operand */
  switch (op->type)
    {
    case VALUE:
      op->operand.valOperand->etype =
        getSpec (op->operand.valOperand->type =
                 copyLinkChain (type));
      return;

    case SYMBOL:
      if (op->operand.symOperand->isitmp)
        op->operand.symOperand->etype =
          getSpec (op->operand.symOperand->type =
                   copyLinkChain (type));
      else
        yylexerror("strange type.");
      return;

    case TYPE:
      op->operand.typeOperand = copyLinkChain (type);
      return;
    }
}

/*-----------------------------------------------------------------*/
/* perform "usual binary conversions"                              */
/*-----------------------------------------------------------------*/

sym_link *convertType (operand ** op1, operand ** op2, int op)
{
  sym_link *ctype;
  sym_link *rtype = operandType (*op2);
  sym_link *ltype = operandType (*op1);

  ctype = computeType (ltype, rtype, op);

  switch (op)
    {
      case '*':
      case '/':
      case '%':
        if (IS_CHAR (getSpec (ltype)) && IS_CHAR (getSpec (rtype)))
          {
            /* one byte operations: keep signedness for code generator */
            return ctype;
          }
        break;
      default:
        break;
    }

  *op1 = geniCodeCast (ctype, *op1, true);
  *op2 = geniCodeCast (ctype, *op2, true);

  return ctype;
}

/*-----------------------------------------------------------------*/
/* geniCodeValueAtAddress - generate intermeditate code for value  */
/*                          at address                             */
/*-----------------------------------------------------------------*/
operand *geniCodeRValue (operand * op, bool force)
{
	iCode *ic;
	sym_link *type = operandType (op);
	sym_link *etype = getSpec (type);

	/* if this is an array & already */
	/* an address then return this*/
	if (/*IS_AGGREGATE (type) || */(IS_PTR (type) && !force && !op->isaddr))
		return operandFromOperand (op);

	/* if this is not an address then must be */
	/* rvalue already so return this one      */
	if (!op->isaddr)
		return op;

	/* Not a temp operand. So, it can't relate to a pointer */
	if (!IS_ITEMP (op) && !force)
	{
		op = operandFromOperand (op);
		op->isaddr = 0;
		return op;
	}
	/* It's a temp operand, but only a normal symbol, ex: int a; */
	if (IS_SPEC (type) && IS_TRUE_SYMOP (op))	
	{
		op = operandFromOperand (op);	//return the purity :D
		op->isaddr = 0;
		return op;
	}
	/* It's a temp operand, and it has address of something...*/
	ic = newiCode (GET_VALUE_AT_ADDRESS, op, NULL);
	if ((IS_PTR (type)||IS_ARRAY(type)) && op->isaddr)	//@NEED
		type = type->next;

	type = copyLinkChain (type);

	IC_RESULT (ic) = newiTempOperand (type, 1);
	IC_RESULT (ic)->isaddr = 0;
	ADDTOCHAIN (ic);

	return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeCast - changes the value from one type to another       */
/*-----------------------------------------------------------------*/
operand * geniCodeCast (sym_link * type, operand * op, bool implicit)
{
	iCode *ic;
	sym_link *optype = operandType(op);
	sym_link *opetype = getSpec (optype);
	sym_link *restype;
	int errors=0;

	/* one of them has size zero then error */
	if (IS_VOID (optype))
	{
		SYNTAX_ERROR;
		return op;
	}

	if (IS_ITEMP (op) && IS_ARRAY (OP_SYMBOL (op)->type))
	{
		//geniCodeArray2Ptr (op);	@NEED
		op->isaddr = 0;
	}

	/* if the operand is already the desired type then do nothing */
	//if (compareType (type, optype) == 1) @NEED
	//	return op;

	/* if this is a literal then just change the type & return */
	if (IS_LITERAL (opetype) && op->type == VALUE && !IS_PTR (type) && !IS_PTR (optype))
	{
		//return operandFromValue (valCastLiteral (type, operandLitValue (op)));	@NEED valCastLiteral
	}

	  /* if casting to/from pointers, do some checking */
	if (IS_PTR(type)) 
	{ // to a pointer
		if (!IS_PTR(optype) && !IS_FUNC(optype) && !IS_AGGREGATE(optype)) 
		{ // from a non pointer
			yylexerror("Can't cast from a non pointer to a pointer");
		} 
		else 
		{	// from a pointer to a pointer
			//it's all ok :D
		}
	}
	else 
	{ // to a non pointer
		if (IS_PTR(optype)) 
		{ // from a pointer
			SYNTAX_ERROR;
		}
	}
 
	if (getSize (type) == getSize (optype) && 
		((IS_SPEC (type) && IS_SPEC (optype)) || (IS_DECL (type) && IS_DECL (optype))))
	{
#if 0
		ic = newiCode ('=', NULL, op);
		IC_RESULT (ic) = newiTempOperand (type, 0);
		if (IS_TRUE_SYMOP (op))
			IC_RESULT (ic)->isaddr = 0;
#else
		return op;
#endif
		
	}
	else
	{
		ic = newiCode (CAST, operandFromLink (type), geniCodeRValue (op, false));
		IC_RESULT (ic) = newiTempOperand (type, 0);
	}
          
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeLabel - will create a Label                             */
/*-----------------------------------------------------------------*/
void geniCodeLabelFromName (char *name)
{
	symbol *sym = newSymbol(name, NestLevel);
	geniCodeLabel(sym);
}
/*-----------------------------------------------------------------*/
/* geniCodeLabel - will create a Label                             */
/*-----------------------------------------------------------------*/
void geniCodeLabel (symbol * label)
{
	iCode *ic;

	ic = newiCodeLabelGoto (LABEL, label);
	ADDTOCHAIN (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeGotoFromName - will create a goto statement             */
/*-----------------------------------------------------------------*/
void geniCodeGotoFromName (char *name)
{
	symbol *sym = newSymbol(name, NestLevel);
	geniCodeGoto(sym);
}
/*-----------------------------------------------------------------*/
/* geniCodeGoto  - will create a Goto                              */
/*-----------------------------------------------------------------*/
void geniCodeGoto (symbol * label)
{
  iCode *ic;

  ic = newiCodeLabelGoto (GOTO, label);
  ADDTOCHAIN (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeMultiply - gen intermediate code for multiplication     */
/*-----------------------------------------------------------------*/
operand *geniCodeMultiply (operand * left, operand * right)
{
	iCode *ic;
	int p2 = 0;
	sym_link *resType;
	sym_link *ltype = operandType(left);
	sym_link *rtype = operandType(right) ;
	sym_link *letype= getSpec(ltype);
	sym_link *retype= getSpec(rtype);
	if (IS_PTR(ltype) || IS_AGGREGATE(ltype))
	{
		yylexerror("'*' : illegal, left operand has type '%s'", printLinkChain(ltype));
		return NULL;
	}
	if (IS_PTR(rtype) || IS_AGGREGATE(rtype))
	{
		yylexerror("'*' : illegal, right operand has type '%s'", printLinkChain(rtype));
		return NULL;
	}
  /* if they are both literal then we know the result */
	if (IS_LITERAL (letype) && IS_LITERAL (retype))
		return operandFromValue (valMult (left->operand.valOperand, right->operand.valOperand));

	if (IS_LITERAL(retype)) 
		//p2 = powof2 ((TYPE_TARGET_ULONG) ulFromVal (right->operand.valOperand));	@NEED
	{

	}
	resType = convertType (&left, &right, '*');

	if (p2 > 0)
	{
		if ((getSize (resType) != getSize (ltype)))
		{
			/* LEFT_OP need same size for left and result, */
			left = geniCodeCast (resType, left, true);
			ltype = operandType (left);
		}
		ic = newiCode (LEFT_OP, left, operandFromValue(valueFromLit(p2))); /* left shift */
	}
	else
	{
		if (getSize (ltype) > 1 || getSize (rtype) > 1)
		{
			if (IS_LITERAL (retype))
				ic = newiCode ('*', right, left); /* multiplication by support routine with one literal */
			else
				ic = newiCode ('*', left, right); /* multiplication by support routine */
			ic->supportRtn = 1;
		}
		else
		{
			ic = newiCode ('*', left, right);   /* normal multiplication */
		}
	}
  IC_RESULT (ic) = newiTempOperand (resType, 1);

  ADDTOCHAIN (ic);
  return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeDivision - gen intermediate code for division           */
/*-----------------------------------------------------------------*/
operand *geniCodeDivision (operand * left, operand * right)
{
	iCode *ic;
	sym_link *resType;
	sym_link *ltype = operandType(left);
	sym_link *rtype = operandType(right) ;
	if (IS_PTR(ltype) || IS_AGGREGATE(ltype))
	{
		yylexerror("'/' : illegal, left operand has type '%s'", printLinkChain(ltype));
		return NULL;
	}
	if (IS_PTR(rtype) || IS_AGGREGATE(rtype))
	{
		yylexerror("'/' : illegal, right operand has type '%s'", printLinkChain(rtype));
		return NULL;
	}
	GENRVALUE;
	resType = convertType (&left, &right, '/'); 
	ic = newiCode ('/', left, right);         /* normal division */
	IC_RESULT (ic) = newiTempOperand (resType, 0);
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeModulus  - gen intermediate code for modulus            */
/*-----------------------------------------------------------------*/
operand *geniCodeModulus (operand * left, operand * right)
{
	iCode *ic;
	sym_link *resType;
	sym_link *ltype = operandType(left);
	sym_link *rtype = operandType(right) ;
	if (IS_PTR(ltype) || IS_AGGREGATE(ltype))
	{
		yylexerror("'%' : illegal, left operand has type '%s'", printLinkChain(ltype));
		return NULL;
	}
	if (IS_PTR(rtype) || IS_AGGREGATE(rtype))
	{
		yylexerror("'%' : illegal, right operand has type '%s'", printLinkChain(rtype));
		return NULL;
	}
	GENRVALUE;
	resType = convertType (&left, &right, '%'); 
	ic = newiCode ('%', left, right);         /* normal division */
	IC_RESULT (ic) = newiTempOperand (resType, 0);
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodePtrPtrSubtract - subtracts pointer from pointer         */
/*-----------------------------------------------------------------*/
operand *geniCodePtrPtrSubtract (operand * left, operand * right)
{
	iCode *ic;
	operand *result;
	sym_link *ltype = operandType(left);
	sym_link *rtype = operandType(right) ;
	sym_link *letype= getSpec(ltype);
    sym_link *retype= getSpec(rtype);

	/* if they are both literals then */
	if (IS_LITERAL (letype) && IS_LITERAL (retype))
	{
		result = operandFromValue (valMinus (left->operand.valOperand, right->operand.valOperand));
		goto subtractExit;
	}

	ic = newiCode ('-', left, right);

	IC_RESULT (ic) = result = newiTempOperand (newIntLink (), 1);
	ADDTOCHAIN (ic);

	subtractExit:
		if (IS_VOID(ltype->next) || IS_VOID(rtype->next)) 
		{
			return result;
		}
		return geniCodeDivision (result, operandFromValue(valueFromLit(getSize (ltype->next))));
}

/*-----------------------------------------------------------------*/
/* geniCodeSubtract - generates code for subtraction               */
/*-----------------------------------------------------------------*/
operand *geniCodeSubtract (operand * left, operand * right)
{	
	iCode *ic;
	int isarray = 0;
	sym_link *resType;
	sym_link *ltype = operandType(left);
	sym_link *rtype = operandType(right) ;
	sym_link *letype= getSpec(ltype);
    sym_link *retype= getSpec(rtype);

	if ((IS_PTR (ltype) || IS_ARRAY (ltype)) && (IS_PTR (rtype) || IS_ARRAY (rtype)))
		return geniCodePtrPtrSubtract (left, right);

	if (IS_LITERAL (letype) && IS_LITERAL (retype)&& left->isLiteral && right->isLiteral)
		return operandFromValue (valMinus (left->operand.valOperand, right->operand.valOperand));

	GENRVALUE;
	if (IS_PTR (ltype) || IS_ARRAY (ltype))
	{
		isarray = left->isaddr;
		right = geniCodeMultiply (right, operandFromValue(valueFromLit( (getSize (ltype->next)))));
		resType = copyLinkChain (IS_ARRAY (ltype) ? ltype->next : ltype);
	}
	else
	{                          
		resType = convertType (&left, &right, '-'); 
	}

	ic = newiCode ('-', left, right);

	IC_RESULT (ic) = newiTempOperand (resType, 1);
	IC_RESULT (ic)->isaddr = (isarray ? 1 : 0);

	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeAdd - generates iCode for addition                      */
/*-----------------------------------------------------------------*/
operand *geniCodeAdd (operand * left, operand * right, bool bArray)
{
	iCode *ic;
	sym_link *resType;
	operand *size;
	int isarray = 0;
	bool indexUnsigned;
	sym_link *ltype = operandType(left);
	sym_link *rtype = operandType(right) ;
	sym_link *letype= getSpec(ltype);
    sym_link *retype= getSpec(rtype);
	
	if (!bArray)
		GENRVALUE;
	if (IS_PTR (ltype) || bArray)
	{
		isarray = left->isaddr;
		if (getSize (ltype->next) != 1)
		{
			if (!IS_ARRAY(ltype->next))
				size  = operandFromValue(valueFromLit(getSize (ltype->next))); //bug
			else
				size  = operandFromValue(valueFromLit(getSize (ltype->next->next))); //bug
			SPEC_USIGN (getSpec (operandType (size))) = 1;
			indexUnsigned = IS_UNSIGNED (getSpec (operandType (right)));
			right = geniCodeMultiply (right, size);
			if (indexUnsigned)
				SPEC_USIGN (getSpec (operandType (right))) = 1;
		}
		resType = copyLinkChain (ltype);
	}
	else
	{ // make them the same size
		resType = convertType (&left, &right, '+');	
	}

	if (IS_LITERAL (letype) && IS_LITERAL (retype)&& left->isLiteral && right->isLiteral)
		return operandFromValue (valPlus (valFromType (ltype), valFromType (rtype)));
	if (IS_VALOP(right) && IS_LITERAL (retype) && !ulFromVal (right->operand.valOperand))
		return left;
	if (IS_VALOP(left) && IS_LITERAL (letype) && !ulFromVal (left->operand.valOperand))
		return right;

	ic = newiCode ('+', left, right);
	IC_RESULT (ic) = newiTempOperand (resType, 1);
	IC_RESULT (ic)->isaddr = (isarray ? 1 : 0);
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeArray - array access                                    */
/*-----------------------------------------------------------------*/
operand *geniCodeArray (operand * left, operand * right)
{
	iCode *ic;
	operand *size;
	sym_link *ltype = operandType (left);
	sym_link *type;
	bool indexUnsigned;
	operand *op;

	if (IS_PTR (ltype))
	{
		if (IS_PTR (ltype->next) && left->isaddr)
		{
			left = geniCodeRValue (left, FALSE);
		}
		return geniCodeDerefPtr (geniCodeAdd (left, right, true), NestLevel);
	}
	if (!IS_ARRAY(ltype->next))
		size  = operandFromValue(valueFromLit(getSize (ltype->next))); //bug
	else
		size  = operandFromValue(valueFromLit(getSize (ltype->next->next))); //bug

	SPEC_USIGN (getSpec (operandType (size))) = 1;
	indexUnsigned = IS_UNSIGNED (getSpec (operandType (right)));
	GENRVALUEOP(right);
	right = geniCodeMultiply (right, size);
	if (IS_VALOP(right) && !ulFromVal (right->operand.valOperand))
	{
		setOperandType(left, ltype->next);
		return left;
	}
	if (indexUnsigned)
		SPEC_USIGN (getSpec (operandType (right))) = 1;

	ic = newiCode ('+', left, right);

	IC_RESULT (ic) = op = newiTempOperand (ltype->next, 0);
	IC_RESULT (ic)->isaddr = 1;

	if (!IS_AGGREGATE (ltype->next))
	{
		IC_RESULT (ic)->isaddr = 1;
		IC_RESULT (ic)->aggr2ptr = 1;
	}
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeStruct - generates intermediate code for structures     */
/*-----------------------------------------------------------------*/
operand *geniCodeStruct (operand * left, operand * right)
{
	iCode *ic;
	sym_link *type = operandType (left);
	sym_link *etype = getSpec (type);
	sym_link *retype;
	symbol *element;
	
	if (!IS_STRUCT(etype))
	{
		yylexerror("Identifier is not a struct/union.");
		return NULL;
	}
	else
		element = getStructElement (SPEC_STRUCT (etype),right->operand.symOperand);
	
	if (!element)
		return;

	assert(IS_SYMOP(right));
	assert(IS_STRUCT (type) || (IS_PTR (type) && IS_STRUCT (type->next)));

	/* add the offset */
	ic = newiCode ('+', left, operandFromValue(valueFromLit((element->offset))));

	IC_RESULT (ic) = newiTempOperand (element->type, 0);
	IC_RESULT (ic)->isaddr = IS_DATA_PTR(type);
	retype = getSpec (operandType (IC_RESULT (ic)));
	SPEC_VOLATILE (retype) |= SPEC_VOLATILE (etype);
	SPEC_CONST (retype) |= SPEC_CONST (etype);
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodePostInc - generate int code for Post increment          */
/*-----------------------------------------------------------------*/
operand *geniCodePostInc (operand * op)
{
	iCode *ic;
	operand *rOp;
	sym_link *optype = operandType (op);
	operand *result;
	operand *rv;
	sym_link *rvtype;
	int size = 0;

	if (IS_ITEMP (op))
		rv = geniCodeRValue(op, (IS_PTR(optype)? true:false));
	else
		rv = op;
	rvtype = operandType (rv);

	rOp = newiTempOperand (rvtype, 0);
	geniCodeAssign (rOp, rv);

	size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1);
	if (size == 0)
		SYNTAX_ERROR;
	ic = newiCode ('+', rv, operandFromValue(valueFromLit (size)));
	IC_RESULT (ic) = result = newiTempOperand (rvtype, 0);
	ADDTOCHAIN (ic);
	geniCodeAssign (op, result);
	return rOp;
}

/*-----------------------------------------------------------------*/
/* geniCodePreInc - generate code for preIncrement                 */
/*-----------------------------------------------------------------*/
operand *geniCodePreInc (operand * op)
{
	iCode *ic;
	sym_link *optype = operandType (op);
	operand *result;
	operand *rv;
	sym_link *rvtype;
	int size = 0;

	if (IS_ITEMP (op))
		rv = geniCodeRValue(op, (IS_PTR(optype)? true:false));
	else
		rv = op;
	rvtype = operandType (rv);
	size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1);
	if (size == 0)
	{
		//werror(W_SIZEOF_VOID);
	}
	ic = newiCode ('+', rv, operandFromValue(valueFromLit (size)));
	IC_RESULT (ic) = result = newiTempOperand (rvtype, 0);
	ADDTOCHAIN (ic);
	geniCodeAssign (op, result);
	return op;		//@SHOULD BE CHECKED
}

/*-----------------------------------------------------------------*/
/* geniCodePostDec - generates code for Post decrement             */
/*-----------------------------------------------------------------*/
operand *geniCodePostDec (operand * op)
{
	iCode *ic;
	operand *rOp;
	sym_link *optype = operandType (op);
	operand *result;
	operand *rv;
	sym_link *rvtype;
	int size = 0;

	//(IS_ITEMP (op) ? geniCodeRValue (op, (IS_PTR (optype) ? true : false)) : op);
	if (IS_ITEMP (op))
		rv = geniCodeRValue(op, (IS_PTR(optype)? true:false));
	else
		rv = op;
	rvtype = operandType (rv);
	/*if (!op->isaddr)
	{
		SYNTAX_ERROR;
		return op;
	}*/

	rOp = newiTempOperand (rvtype, 0);
	geniCodeAssign (rOp, rv);

	size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1);
	if (size == 0)
		SYNTAX_ERROR;
	ic = newiCode ('-', rv, operandFromValue(valueFromLit (size)));
	IC_RESULT (ic) = result = newiTempOperand (rvtype, 0);
	ADDTOCHAIN (ic);
	geniCodeAssign (op, result);
	return rOp;
}

/*-----------------------------------------------------------------*/
/* geniCodePreDec - generate code for pre  decrement               */
/*-----------------------------------------------------------------*/
operand *geniCodePreDec (operand * op, bool lvalue)
{
	iCode *ic;
	sym_link *optype = operandType (op);
	operand *result;
	operand *rv;
	sym_link *rvtype;
	int size = 0;

	if (IS_ITEMP (op))
		rv = geniCodeRValue(op, (IS_PTR(optype)? true:false));
	else
		rv = op;
	rvtype = operandType (rv);
	/*if (!op->isaddr)
	{
		SYNTAX_ERROR;
		return op;
	}*/

	size = (IS_PTR (rvtype) ? getSize (rvtype->next) : 1);
	if (size == 0)
	{
		SYNTAX_ERROR;
	}
	ic = newiCode ('-', rv, operandFromValue(valueFromLit (size)));
	IC_RESULT (ic) = result = newiTempOperand (rvtype, 0);
	ADDTOCHAIN (ic);
	geniCodeAssign (op, result);
	return op;		//@SHOULD BE CHECKED
}

/*-----------------------------------------------------------------*/
/* geniCodeBitwise - gen int code for bitWise operators(&,|,^,!)   */
/*-----------------------------------------------------------------*/
operand *geniCodeBitwise (operand * left, operand * right, int oper)
{
	iCode *ic;
	sym_link * resultType;
	GENRVALUE;
	resultType = convertType(&left, &right, oper);
	left = geniCodeCast (resultType, left, true);
	right = geniCodeCast (resultType, right, true);
	ic = newiCode (oper, left, right);
	IC_RESULT (ic) = newiTempOperand (resultType, 0); 
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}


/*-----------------------------------------------------------------*/
/* geniCodeAddressOf - gens icode for '&' address of operator      */
/*-----------------------------------------------------------------*/
operand *geniCodeAddressOf (operand * op)
{
	iCode *ic;
	sym_link *p;
	sym_link *optype = operandType (op);
	sym_link *opetype = getSpec (optype);

	if (IS_ITEMP (op) && op->isaddr && IS_PTR (optype))
	{
		op = operandFromOperand (op);
		op->isaddr = 0;
		return op;
	}

	p = newLink (DECLARATOR);
	p->next = copyLinkChain (optype);
	if (IS_ITEMP (op))
	{
		setOperandType (op, p);
		op->isaddr = 0;
		return op;
	}
	ic = newiCode (ADDRESS_OF, op, NULL);
	IC_RESULT (ic) = newiTempOperand (p, true);
	IC_RESULT (ic)->isaddr = 0;
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}




/*-----------------------------------------------------------------*/
/* geniCodeUnaryMinus - does a unary minus of the operand          */
/*-----------------------------------------------------------------*/
operand *geniCodeUnaryMinus (operand * op)
{
	iCode *ic;
	sym_link *optype = operandType (op);
	GENRVALUEOP(op);
	if (!IS_INTEGRAL(optype))
		_error();
	if (IS_LITERAL (optype))
		return operandFromValue(valueFromLit((-ulFromVal (op->operand.valOperand))));	

	ic = newiCode (UNARYMINUS, op, NULL);
	IC_RESULT (ic) = newiTempOperand (optype, 0);
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}


/*-----------------------------------------------------------------*/
/* geniCodeLeftShift - gen i code for left shift                   */
/*-----------------------------------------------------------------*/
operand *geniCodeLeftShift (operand * left, operand * right)
{
	iCode *ic;
	sym_link *resType;
	GENRVALUE;
	ic = newiCode (LEFT_OP, left, right);
	resType = convertType (&left, &right, LEFT_OP);
	IC_RESULT (ic) = newiTempOperand (resType, 0);
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}


/*-----------------------------------------------------------------*/
/* geniCodeRightShift - gen i code for right shift                 */
/*-----------------------------------------------------------------*/
operand *geniCodeRightShift (operand * left, operand * right)
{
	iCode *ic;
	GENRVALUE;
	ic = newiCode (RIGHT_OP, left, right);
	IC_RESULT (ic) = newiTempOperand (operandType (left), 0);
	ADDTOCHAIN (ic);
	return IC_RESULT (ic);
}


/*-----------------------------------------------------------------*/
/* geniCodeUnary - for a generic unary operation                   */
/*-----------------------------------------------------------------*/
operand *geniCodeUnary (operand * op, int oper)
{
  iCode *ic;
  GENRVALUEOP(op);
  ic = newiCode (oper, op, NULL);
  IC_RESULT (ic) = newiTempOperand (operandType (op), 0);
  ADDTOCHAIN (ic);
  return IC_RESULT (ic);
}


/*-----------------------------------------------------------------*/
/* geniCodeAssign - generate code for assignment                   */
/*-----------------------------------------------------------------*/
operand *geniCodeAssign (operand * left, operand * right)	//@NEED
{
	iCode *ic;
	sym_link *ltype = operandType (left);
	sym_link *rtype = operandType (right);
	operand *opl = left;
	operand *opr = right;

	if (left->isaddr && IS_ITEMP (left))
	{
		opl = geniCodeRValue(left, FALSE);
	}
	if (right->isaddr && IS_ITEMP(right))
	{
		opr = geniCodeRValue(right, FALSE);
	}
	//else if (compareType (ltype, rtype) < 0)
	//	right = geniCodeCast (ltype, right, TRUE);

	ic = newiCode ('=', NULL, opr);
	IC_RESULT (ic) = opl;
	ADDTOCHAIN (ic);
	return right;
}


/*-----------------------------------------------------------------*/
/* geniCodeReturn - gen icode for 'return' statement               */
/*-----------------------------------------------------------------*/
void geniCodeReturn (operand * op)
{
	iCode *ic;
	if (op)
		op = geniCodeRValue (op, false);
	ic = newiCode (RETURN, op, NULL);
	ADDTOCHAIN (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeCall - gen icode for call procedure		               */
/*-----------------------------------------------------------------*/
operand *geniCodeCall (operand *func, operand *params)
{
	iCode *ic;
	symbol *sym;
	value *args, *pargs;
	operand *p;
	sym_link *type = func->operand.symOperand->type;
	int numParams = 0;
	int cmpType;
	
	/* check function name */
	sym = findSymWithLevel(SymbolTab, func->operand.symOperand);
	if (!sym)
	{
		yylexerror("Undefined identifier '%s'", func->operand.symOperand->name);
		return NULL;
	}

	while (type && !IS_FUNC(type))
		type = type->next;

	if (!type || !IS_FUNC(type))
	{
		yylexerror("Undefined function '%s'", func->operand.symOperand->name);
		return NULL;
	}

	/* check params variable */
	args = FUNC_ARGS(type);
	p = params;
	while (p)
	{
		if (p->type == SYMBOL && !IS_ITEMP(p))
		{
			/* check sym name from level 0 to the nest level of this identifier */
			sym = resolveArgSymbols(p->operand.symOperand, currFunc);
			if (!sym)
				sym = findSymWithLevel(SymbolTab, p->operand.symOperand);

			if (!sym ||
				(IS_ARGUMENT(sym) && currFunc != sym->localof && strcmp(sym->localof->name, currFunc->name) != 0))
			{
				yylexerror("Undefined identifier '%s'", p->operand.symOperand->name);
				return NULL;
			}
		}
		
		numParams++;
		p = p->next;
	}
  
	/* check number of parameter and type */
	p = params;
	pargs = args;
	while (p && pargs)
	{
		if (p->type == SYMBOL)
		{
			cmpType = compareType(pargs->sym->type, p->operand.symOperand->type);
			if (cmpType == 0)
			{
				yylexerror("different type of: '%s' -> '%s', see above delaration",
							printLinkChain(p->operand.symOperand->type),
							printLinkChain(pargs->sym->type));
				return NULL;
			}
		}

		p = p->next;
		pargs = pargs->next;
	}

	if (p && !pargs)
	{
		yylexerror("too more argument for call");
		return NULL;
	}
	else if (!p && pargs)
	{
		yylexerror("too few argument for call");
		return NULL;
	}

	/* all parameter and type is valid */
	p = params;
	pargs = args;
	while (p && pargs)
	{
		operand *tmp = p;
		if (p->type == SYMBOL)
		{	
			cmpType = compareType(pargs->sym->type, p->operand.symOperand->type);
			if (cmpType==-1)
				tmp = geniCodeCast(pargs->sym->type, p,TRUE);
		}
		ic = newiCode(SEND, tmp, NULL);
		ADDTOCHAIN (ic);
		p = p->next;
		pargs = pargs->next;
	}

	ic = newiCode (CALL, func, NULL);
	IC_RESULT(ic) = newiTempOperand(copyLinkChain(type), TRUE);
	ADDTOCHAIN (ic);
	return IC_RESULT(ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeFunction - gen icode for begining function	statements */
/*-----------------------------------------------------------------*/
void geniCodeFunction (operand * op)
{
	iCode *ic;
	operand *opFunc;
	value *val;
	sym_link *type = op->operand.symOperand->type;

	ic = newiCode (9, op, NULL);
	ADDTOCHAIN (ic);

	while (type && !IS_FUNC(type))
		type = type->next;

	assert(type && IS_FUNC(type));
	val = FUNC_ARGS(type);

	while (val)
	{
		bSkipGenGetAddress = 1;
		opFunc = operandFromValue(val);
		ic = newiCode(RECEIVE, op, NULL);
		IC_RESULT(ic) = opFunc;
		ADDTOCHAIN (ic);
		val = val->next;
	}
}

/*-----------------------------------------------------------------*/
/* geniCodeEndFunction - gen icode for ending function	statements */
/*-----------------------------------------------------------------*/
void geniCodeEndFunction (operand * op)
{
	iCode *ic;

	ic = newiCode (ENDFUNCTION, op, NULL);
	ADDTOCHAIN (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeDerefPtr - dereference pointer with '*'                 */
/*-----------------------------------------------------------------*/
operand *geniCodeDerefPtr (operand * op, int lvl)
{
	sym_link *rtype;
	sym_link *optype = operandType (op);

	if (IS_ARRAY (optype))
	{
		return geniCodeArray (op, operandFromValue(valueFromLit (0)), lvl);
	}

	if (IS_TRUE_SYMOP (op))
	{
		op->isaddr = 1;
		op = geniCodeRValue (op, TRUE);
	}
	optype = operandType (op);
	rtype = copyLinkChain (optype->next);
	
	if (op->isaddr==0)
		op->isaddr = (IS_PTR (rtype) || IS_STRUCT (rtype));
	//if IS_PTR(optype->next)
	//op = geniCodeRValue (op, TRUE);
	setOperandType (op, rtype);

	return op;
}
/*-----------------------------------------------------------------*/
/* geniCodeIfx - gen icode for condition statement				   */
/*-----------------------------------------------------------------*/
void geniCodeIfx (operand * op, symbol *trueLabel, symbol *falseLabel)
{
	iCode *ic;
	if (IS_VOID(operandType(op))) 
	{
		SYNTAX_ERROR;
	}

	ic = newiCode (IFX, NULL, NULL);
	IC_COND (ic) = op;
	IC_TRUE (ic) = trueLabel;
	IC_FALSE (ic) = falseLabel;
	ADDTOCHAIN (ic);
}

/*-----------------------------------------------------------------*/
/* geniCodeLogic - gen icode for logical statement				   */
/*-----------------------------------------------------------------*/
operand *geniCodeLogic (operand *left, operand *right, int op)
{
	iCode *ic;
	GENRVALUE;
	ic = newiCode (op, left, right);
	IC_RESULT(ic) = newiTempOperand(newCharLink(), 1);
	ADDTOCHAIN (ic);
	return IC_RESULT(ic);
}

/*-----------------------------------------------------------------*/
/* reverseICChain - gets from the list and creates a linkedlist    */
/*-----------------------------------------------------------------*/
iCode *reverseiCChain ()
{
  iCode *loop = NULL;
  iCode *prev = NULL;

  while ((loop = getSet (&iCodeChain)))
    {
      loop->next = prev;
      if (prev)
        prev->prev = loop;
      prev = loop;
    }

  iCodePrintAll(prev, "iCode.txt");
  return prev;
}



void iCodePrint(iCode *ic, FILE *f)
{
	if (!ic||!f)
		return;
	switch(ic->op)
	{	
		case '!' :
			fprintf(f, "\n%s = !(%s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)));
            break;

        case '~' :
			fprintf(f, "\n%s = ~(%s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)));
            break;

        case UNARYMINUS:
			fprintf(f, "\n%s = -%s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)));
            break;

        case CALL:
			fprintf(f, "\n%s = CALL(%s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)));
            break;

        case 9:
			fprintf(f, "\nBEGIN FUNCTION : %s", PRINT_OP(IC_LEFT(ic)));
            break;

        case ENDFUNCTION:
			fprintf(f, "\nEND FUNCTION");
            break;

        case RETURN:
			if (IC_LEFT(ic))
				fprintf(f, "\nRETURN %s",  PRINT_OP(IC_LEFT(ic)));
			else
				fprintf(f, "\nRETURN");
            break;

        case LABEL:
			fprintf(f, "\n%s:", ic->label->name);
            break;

        case GOTO:
			fprintf(f, "\nGOTO : %s", ic->label->name);
            break;

        case '+' :
			fprintf(f, "\n%s = %s + %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case '-' :
			fprintf(f, "\n%s = %s - %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case '*' :
			fprintf(f, "\n%s = %s * %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case '/' :
			fprintf(f, "\n%s = %s / %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case '%' :
			fprintf(f, "\n%s = %s MOD %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case '>' :
			fprintf(f, "\n%s = (%s > %s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case '<' :
			fprintf(f, "\n%s = (%s < %s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case NE_OP:
			fprintf(f, "\n%s = (%s != %s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case EQ_OP:
			fprintf(f, "\n%s = (%s == %s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case AND_OP:
			fprintf(f, "\n%s = (%s && %s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case OR_OP:
			fprintf(f, "\n%s = (%s || %s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case '^' :
			fprintf(f, "\n%s = %s ^ %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case '|' :
			fprintf(f, "\n%s = %s | %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case BITWISEAND:
			fprintf(f, "\n%s = %s & %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case LEFT_OP:
			fprintf(f, "\n%s = %s << %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

		case RIGHT_OP:
			fprintf(f, "\n%s = %s >> %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case GET_VALUE_AT_ADDRESS:
			fprintf(f, "\n%s = *(%s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)));
            break;

        case '=' :
			fprintf(f, "\n%s = %s", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case IFX:
			fprintf(f, "\nIF%s(%s) \n\tGOTO : %s", IC_TRUE(ic)?"TRUE":"FALSE", PRINT_OP(IC_COND(ic))
				, IC_TRUE(ic)?IC_TRUE(ic)->name:IC_FALSE(ic)->name);
            break;

        case ADDRESS_OF:
			fprintf(f, "\n%s = &(%s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)));
            break;

        case CAST:
			fprintf(f, "\n%s = CAST(%s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_RIGHT(ic)));
            break;

        case RECEIVE:
			fprintf(f, "\n%s = RECEIVE(%s)", PRINT_OP(IC_RESULT(ic)), PRINT_OP(IC_LEFT(ic)));
            break;

        case SEND:
			fprintf(f, "\nSEND : %s", PRINT_OP(IC_LEFT(ic)));
            break;

        default :
            break; 
	}
}

void iCodePrintAll(iCode *ic, char *filename)
{
	iCode *p;
	FILE *f;
	f = fopen(filename, "wt");
	if (!f)
		return;

	for (p = ic ; p ; p = p->next) 
		iCodePrint(p, f);
	fclose(f);
}